home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 June / EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso / earcd / comm2 / statty25.lha / statty / statty.rexx < prev   
OS/2 REXX Batch file  |  1996-05-08  |  24KB  |  803 lines

  1. /*
  2. ** $VER: statty.rexx 2.5 (7.5.96) Rolf Rotvel
  3. **
  4. ** Uses rexxtricks.library
  5. */ 
  6.  
  7. log.path    = 'logs:spot.log.max'     /* Path to tosser logfile */
  8. area.path   = 'mail:max/spot.areas'   /* Path to tosser areas file */
  9. out.path    = 'fido:statty.out'       /* Path to Statty's outputfile */
  10. db.path     = 'fido:statty.db'        /* Path to Statty's database */
  11.  
  12. keeplog?    = 1                 /* Boolean. Create backup of logfile */
  13. keeplogname = ''                /* Name of backup log (Default: <log.path>.statty) */ 
  14.  
  15. allareas?   = 1                 /* Boolean. Include areas with no flow in output */
  16. toyou?      = 1                 /* Boolean. Show msgs to (Or from) you in output */
  17.  
  18. excludefile = ''                /* Path to excludefile. '' if none */
  19.  
  20. /*
  21. ** End of cfg.
  22. */
  23. arg tosser
  24.  
  25. signal on syntax
  26. signal on error
  27.  
  28. call addlib('rexxsupport.library', 0, -30, 0)
  29. call addlib('rexxtricks.library', 0, -30, 0)
  30. call pragma('p', -1)
  31.  
  32. template = 'FZ=FOOZLE/S,S=SPOT/S,MM=MAILMANAGER/S '
  33. options prompt template
  34.  
  35. PARSEARG:
  36. select
  37.     when tosser = 'FZ' | tosser = 'FOOZLE' then tosser = 'Foozle'
  38.     when tosser = 'S'  | tosser = 'SPOT' then tosser = 'Spot'
  39.     when tosser = 'MM' | tosser = 'MAILMANAGER' then tosser = 'MailManager'
  40.     when tosser = '' then do
  41.         say 'Required argument missing'
  42.         say template
  43.         exit
  44.     end     
  45.     when tosser = '?' then do
  46.         pull tosser
  47.         signal parsearg
  48.     end
  49.     otherwise do
  50.         say 'Bad argument'
  51.         say template
  52.         exit
  53.     end
  54. end
  55.  
  56. if ~exists(log.path) then call errorexit ('Can''t find '||log.path)
  57. if ~exists(area.path) then call errorexit ('Can''t find '||area.path)
  58.  
  59. start.thisdb = date()||' '||left(time(), 5)
  60.  
  61. if keeplog? then do
  62.     if keeplogname ~= '' then oldpath = makepath(pathpart(log.path), keeplogname)
  63.     else oldpath = log.path||'.statty'
  64.  
  65.     say 'Backing up log as '||oldpath
  66.  
  67.     if exists(oldpath) then call appendfile(log.path, oldpath)
  68.     else call copyfile(log.path, oldpath)
  69. end
  70.  
  71. exc = ''
  72. if excludefile ~= '' then do
  73.     if open('tmp', excludefile, 'r') then do
  74.         say 'Reading '||excludefile
  75.         exc = readch('tmp', 65535)
  76.         call close('tmp')
  77.     end
  78. end
  79.  
  80. if exists(db.path) then do
  81.     say 'Reading '||db.path
  82.     if ~readfile(db.path, line) then call errorexit ('Error reading '||db.path)
  83.     parse var line.1 '"' start.firstdb '"' '"' start.lastdb '"' areastamp total.dbmsgs total.dbtoyou total.dbfromyou .
  84.  
  85.     parse value statef(area.path) with . . . . days mins ticks .
  86.     chkstamp = days||mins||ticks
  87.  
  88.     if areastamp ~= chkstamp then do
  89.         areastamp = chkstamp
  90.  
  91.         num = 1
  92.         area.length = 0
  93.  
  94.         interpret 'call '||tosser||'area'
  95.  
  96.         do d = 2 to line.0
  97.             parse var line.d _name _msgs _toyou _fromyou  .
  98.             if lsearch(_name, area.name) = -1 then iterate
  99.             db.name.num = _name
  100.             db.msgs.num = _msgs
  101.             db.toyou.num = _toyou
  102.             db.fromyou.num = _fromyou
  103.             num = num + 1
  104.         end
  105.         db.name.0 = num - 1
  106.  
  107.     end
  108.     else do 
  109.         num = 1
  110.         area.length = 0
  111.  
  112.         do d = 2 to line.0
  113.             parse var line.d _name _msgs _toyou _fromyou .
  114.  
  115.             if pos('"'||_name||'"', exc) > 0 then iterate
  116.             
  117.             area.name.num = _name
  118.             area.length = max(area.length, length(_name))
  119.             db.name.num = _name
  120.             db.msgs.num = _msgs
  121.             db.toyou.num = _toyou
  122.             db.fromyou.num = _fromyou
  123.             num = num + 1
  124.         end
  125.         area.name.0 = num - 1
  126.         db.name.0 = area.name.0
  127.     end
  128. end
  129. else do
  130.     area.length = 0
  131.     interpret 'call '||tosser||'area'
  132.  
  133.     start.firstdb = start.thisdb
  134.     start.lastdb = start.thisdb
  135.  
  136.     parse value statef(area.path) with . . . . days mins ticks .
  137.     areastamp = days||mins||ticks
  138.  
  139.     total.dbmsgs = 0
  140.     total.dbtoyou = 0
  141.     total.dbfromyou = 0
  142.  
  143.     do a = 1 to area.name.0
  144.         db.name.a = area.name.a
  145.         db.msgs.a = 0 
  146.         db.toyou.a = 0
  147.         db.fromyou.a = 0
  148.     end
  149. end
  150.  
  151. total.logmsgs = 0
  152. total.logtoyou = 0
  153. total.logfromyou = 0
  154.  
  155. interpret 'call '||tosser||'log'
  156.  
  157. if total.logmsgs = 0 then say 'No new messages to process. Exiting'
  158. else do
  159.     call calculatedb
  160.     call putdb
  161.     call sortoutput
  162.     call genoutput
  163. end
  164. if ~delete(log.path) then call errorexit('Error deleting '||log.path)
  165. say 'Finished'
  166. exit
  167.  
  168.  
  169. ERROREXIT: 
  170. say arg(1) 
  171. exit 10
  172.  
  173.  
  174. SPOTAREA: procedure expose area. exc 
  175. say 'Reading '||area.path
  176. if ~readfile(area.path, line) then call errorexit('Error reading '||area.path)
  177.  
  178. num = 1
  179.  
  180. do a = 1 to line.0
  181.     chk = upper(line.a)
  182.  
  183.     /* Skip separator, bad, default & netmail areas */
  184.     if pos(' SEPARATOR', chk) > 0 | pos(' BAD', chk) > 0 |,
  185.        pos(' DEFAULT', chk) > 0 | pos(' NETMAIL', chk) > 0 then iterate
  186.     parse var line.a . '"' . '"' '"' _name '"'
  187.  
  188.     /* Is areaname in excludefile? */
  189.     if pos('"'||_name||'"', exc) > 0 then iterate
  190.  
  191.     /* A duplicate areaname?!? */
  192.     if lsearch(_name, area.name) ~= -1 then call errorexit,
  193.         ('Found duplicate areaname "'||_name||'" twice in '||area.path||'!')
  194.  
  195.     area.name.num = _name
  196.     area.name.0 = num       /* Needed for lsearch() */                    
  197.     area.length = max(area.length, length(_name))
  198.     num = num + 1
  199.  
  200. end
  201. return
  202.  
  203.  
  204. FOOZLEAREA: procedure expose area. exc
  205. say 'Reading '||area.path
  206. if ~open('tmp', area.path, 'r') then call errorexit('Error reading '||area.path)
  207.  
  208. num = 1
  209. null = '0'x
  210.  
  211. do forever
  212.     _name = readch('tmp', 24)                       /* Read areaname */
  213.     if eof('tmp') then leave                        /* Break condition */
  214.     tag = upper(strip(readch('tmp', 24), 't', null) /* Read tagname */
  215.     dir = compress(readch('tmp', 32), null)         /* Read areadir */
  216.     call seek('tmp', 128 + 520)                     /* Skip rest of area definition */
  217.                                                     /* Iterate if not valid area ? */
  218.     if dir = '' | ~exists(dir) | tag = 'BAD' |,     
  219.        tag = 'MATRIX' then iterate
  220.  
  221.     _name = strip(_name, 't', null)
  222.  
  223.     if pos('"'||_name||'"', exc) > 0 then iterate       /* Check excludefile */
  224.  
  225.                                                     /* A duplicate areaname?!? */
  226.     if lsearch(_name, area.name) ~= -1 then call errorexit,
  227.         ('Found duplicate areaname "'||_name||'" twice in '||area.path||'!')
  228.  
  229.     area.name.num = _name
  230.     area.name.0 = num                               /* Needed for lsearch() */
  231.     area.length = max(area.length, length(_name))
  232.     num = num + 1
  233. end
  234.  
  235. call close('tmp')
  236. return
  237.  
  238.  
  239. MAILMANAGERAREA: procedure expose area. exc
  240. say 'Reading '||area.path
  241. if ~readfile(area.path, line) then call errorexit('Error reading '||area.path)
  242.  
  243. taglen = 20     /* In MM log tagnames are cut off after <taglen> chars */
  244. num = 1
  245. start = 1
  246.  
  247. do forever
  248.     /* Skip bad, netmail, fileecho & tick areas */
  249.     a = lsearch("'#ECHOAREA *", line, start,, pattern)
  250.     if a = -1 then leave            
  251.     start = a + 1
  252.  
  253.     parse var line.a . '"' . '"' _name .
  254.     if pos('"'||_name||'"', exc) > 0 then iterate
  255.  
  256.     if length(_name) > taglen then do
  257.         subname = left(_name, taglen)
  258.         chk = lsearch(subname||'*', area.name,,, 'p') 
  259.         /* Found two tagnames where first <taglen> chars are the same */
  260.         if chk ~= -1 then call tagerror(taglen, _name, area.name.chk)
  261.     end
  262.  
  263.     area.name.num = _name
  264.     area.name.0 = num
  265.     area.length = max(area.length, length(area.name.num))
  266.     num = num + 1
  267. end
  268. return
  269.  
  270. TAGERROR: procedure
  271. nl = '0a'x
  272. call errorexit('In MM log tagnames are cut off after '||arg(1)||' chars.'||nl||,
  273.                arg(2)||' and'||nl||,
  274.                arg(3)||nl||,
  275.                'will therefore look the same to Statty.'||nl||,
  276.                'You must include one of them in the excludefile.')
  277. return   /* Never returns...*/
  278.  
  279.  
  280. SPOTLOG: procedure expose total. log. area.
  281. say 'Reading '||log.path
  282. if ~readfile(log.path, line) then call errorexit('Error reading '||log.path)
  283.  
  284. num = 1
  285.  
  286. startexp = 'Export startet'
  287. endexp   = 'Export ended'
  288.  
  289. export? = 0
  290.  
  291. do l = 1 to line.0
  292.     first = left(line.l, 1)
  293.     select
  294.         when pos(startexp, line.l) > 0 then export? = 1
  295.         when pos(endexp, line.l) > 0 then export? = 0
  296.         when first = '*' | first = '!' then do
  297.             parse var line.l . "'" _name "'" rest
  298.  
  299.             /* Iterate if it's not a valid areaname */
  300.             if lsearch(_name, area.name) = -1 then iterate
  301.  
  302.             /* Find amount of msgs imported */
  303.             wds = words(rest)
  304.             do w = 1 to wds
  305.                 _msgs = word(rest, w)
  306.                 if datatype(_msgs, 'w') then do
  307.                     total.logmsgs = total.logmsgs + _msgs
  308.                     leave
  309.                 end
  310.             end
  311.  
  312.             /* Parse rest of line if any msgs for you */
  313.             if ~export? then do
  314.                 if first = '*' then do ww = w + 1 to wds
  315.                     _toyou = word(rest, ww)
  316.                     if datatype(_toyou, 'w') then do
  317.                         total.logtoyou = total.logtoyou + _toyou
  318.                         leave
  319.                     end
  320.                 end
  321.                 else _toyou = 0
  322.  
  323.                 /* Is it first time we find this areaname in logfile? */
  324.                 chk = lsearch(_name, log.name)
  325.                 if chk = -1 then do         /* Initialize variables */
  326.                     log.name.num = _name
  327.                     log.msgs.num = _msgs
  328.                     log.toyou.num = _toyou
  329.                     log.fromyou.num = 0
  330.                     log.name.0 = num        /* Need this for lsearch() */
  331.                    num = num + 1
  332.                 end
  333.                 else do                     /* Update variables */
  334.                     log.msgs.chk = log.msgs.chk + _msgs
  335.                     log.toyou.chk = log.toyou.chk + _toyou
  336.                 end
  337.             end
  338.             else do /* Export! */
  339.                 chk = lsearch(_name, log.name)
  340.                 if chk = -1 then do         /* Initialize variables */
  341.                     log.name.num = _name
  342.                     log.msgs.num = _msgs
  343.                     log.toyou.num = 0
  344.                     log.fromyou.num = _msgs
  345.                     log.name.0 = num        /* Need this for lsearch() */
  346.                     num = num + 1
  347.                 end
  348.                 else do                     /* Update variables */
  349.                     log.msgs.chk = log.msgs.chk + _msgs
  350.                     log.fromyou.chk = log.fromyou.chk + _msgs
  351.                 end
  352.                 total.logfromyou = total.logfromyou + _msgs
  353.             end
  354.         end
  355.         otherwise nop
  356.     end
  357. end
  358. return
  359.  
  360.  
  361. FOOZLELOG: procedure expose total. log. area.
  362. say 'Reading '||log.path
  363. if ~readfile(log.path, line) then call errorexit('Error reading '||log.path)
  364.  
  365. num = 1
  366.  
  367. do l = 1 to line.0
  368.     if word(line.l, 4) = 'Area' then do
  369.         parse var line.l . '"' _name '"' rest
  370.         /* Iterate if it's not a valid areaname */
  371.         if lsearch(_name, area.name) = -1 then iterate
  372.         /* Find amount of msgs imported */
  373.         wds = words(rest)
  374.         do w = 1 to wds
  375.             _msgs = word(rest, w)
  376.             if datatype(_msgs, 'w') then do
  377.                 total.logmsgs = total.logmsgs + _msgs
  378.                 leave
  379.             end
  380.         end
  381.  
  382.         /* Parse rest of line if any msgs for you */
  383.         if right(line.l, 7) = 'for you' then do ww = w + 1 to wds
  384.             _toyou = word(rest, ww)
  385.             if datatype(_toyou, 'w') then do
  386.                 total.logtoyou = total.logtoyou + _toyou
  387.                 leave
  388.             end
  389.         end
  390.         else _toyou = 0
  391.  
  392.         /* Is it first time we find this areaname in logfile? */
  393.         chk = lsearch(_name, log.name)
  394.         if chk = -1 then do         /* Initialize variables */
  395.             log.name.num = _name
  396.             log.msgs.num = _msgs
  397.             log.toyou.num = _toyou
  398.             log.fromyou.num = 0     /* Foozle doesn't support this...*/
  399.             log.name.0 = num        /* Need this for lsearch() */
  400.             num = num + 1
  401.         end
  402.         else do                     /* Update variables */
  403.             log.msgs.chk = log.msgs.chk + _msgs
  404.             log.toyou.chk = log.toyou.chk + _toyou
  405.         end
  406.     end
  407. end
  408. return
  409.  
  410.  
  411. MAILMANAGERLOG: procedure expose total. log. area.
  412. say 'Reading '||log.path
  413. if ~readfile(log.path, line) then call errorexit('Error reading '||log.path)
  414.  
  415. num = 1
  416.  
  417. startimp = 'Import Statistics'
  418. endimp   = 'Import Used'
  419.  
  420. startexp = 'Start Export Function'
  421. endexp   = 'End Export Function'
  422.  
  423. action = ''
  424.  
  425. do l = 1 to line.0
  426.     if action = '' then do
  427.         select
  428.             when pos(startimp, line.l) > 0 then action = 'imp'
  429.             when pos(startexp, line.l) > 0 then action = 'exp'
  430.             otherwise nop
  431.         end
  432.     end
  433.     else do
  434.         select
  435.             when pos(endimp, line.l) > 0 then action = ''
  436.             when pos(endexp, line.l) > 0 then action = ''
  437.             when word(line.l, 7) = 'Area' then do
  438.                 if action = 'imp' then do
  439.                     parse var line.l . 'Area' _name _msgs '(' _toyou ')'
  440.  
  441.                     /* Iterate if it's not a valid areaname */
  442.                     /* Have to use a pattern here. MM doesn't show full tagname in log */
  443.                 
  444.                     if lsearch(_name||'*', area.name,,, 'p') = -1 then iterate
  445.  
  446.                     _msgs = strip(_msgs)
  447.                     total.logmsgs = total.logmsgs + _msgs
  448.                     _toyou = strip(_toyou)
  449.                     total.logtoyou = total.logtoyou + _toyou
  450.  
  451.                     /* Is it first time we find this areaname in logfile? */
  452.                     chk = lsearch(_name, log.name)
  453.                     if chk = -1 then do         /* Initialize variables */
  454.                         log.name.num = _name
  455.                         log.msgs.num = _msgs
  456.                         log.toyou.num = _toyou
  457.                         log.fromyou.num = 0
  458.                         log.name.0 = num        /* Need this for lsearch() */
  459.                         num = num + 1
  460.                     end
  461.                     else do                     /* Update variables */
  462.                         log.msgs.chk = log.msgs.chk + _msgs
  463.                         log.toyou.chk = log.toyou.chk + _toyou
  464.                     end
  465.                 end
  466.                 else do     /* Standalone export */
  467.                     parse var line.l . 'Area' _name _fromyou .
  468.  
  469.                     if lsearch(_name||'*', area.name,,, 'p') = -1 then iterate
  470.     
  471.                     total.logmsgs = total.logmsgs + _fromyou
  472.                     total.logfromyou = total.logfromyou + _fromyou
  473.  
  474.                     chk = lsearch(_name, log.name)
  475.                     if chk = -1 then do         /* Initialize variables */
  476.                         log.name.num = _name
  477.                         log.msgs.num = _fromyou
  478.                         log.toyou.num = 0
  479.                         log.fromyou.num = _fromyou
  480.                         log.name.0 = num        /* Need this for lsearch() */
  481.                         num = num + 1
  482.                     end
  483.                     else do                     /* Update variables */
  484.                         log.msgs.chk = log.msgs.chk + _fromyou
  485.                         log.fromyou.chk = log.fromyou.chk + _fromyou
  486.                     end
  487.                 end
  488.             end
  489.             otherwise nop
  490.         end
  491.     end
  492. end
  493. return
  494.  
  495.  
  496. CALCULATEDB: procedure expose area. log. db.
  497. say 'Calculating database'
  498.  
  499. area.maxmsgs = 0
  500. area.maxtoyou = 0
  501. area.maxnewmsgs = 0
  502. area.maxnewtoyou = 0
  503. area.maxfromyou = 0
  504. area.maxnewfromyou = 0
  505.  
  506. do a = 1 to area.name.0
  507.     chklog = lsearch(area.name.a, log.name)
  508.     if chklog = -1 then do 
  509.         area.newmsgs.a = 0
  510.         area.newtoyou.a = 0
  511.         area.newfromyou.a = 0
  512.     end
  513.     else do
  514.         area.newmsgs.a = log.msgs.chklog
  515.         area.newtoyou.a = log.toyou.chklog
  516.         area.newfromyou.a = log.fromyou.chklog
  517.     end
  518.  
  519.     chkdb = lsearch(area.name.a, db.name)
  520.     if chkdb = -1 then do 
  521.         dbmsgs = 0
  522.         dbtoyou = 0
  523.         dbfromyou = 0
  524.     end
  525.     else do
  526.         dbmsgs = db.msgs.chkdb
  527.         dbtoyou = db.toyou.chkdb
  528.         dbfromyou = db.fromyou.chkdb
  529.     end
  530.  
  531.     /* These variables needed when calculating/formatting output */
  532.     area.msgs.a = area.newmsgs.a + dbmsgs
  533.     area.toyou.a = area.newtoyou.a + dbtoyou
  534.     area.fromyou.a = area.newfromyou.a + dbfromyou
  535.  
  536.     area.maxmsgs = max(area.msgs.a, area.maxmsgs)
  537.     area.maxtoyou = max(area.toyou.a, area.maxtoyou)
  538.     area.maxfromyou = max(area.fromyou.a, area.maxfromyou)
  539.  
  540.     area.maxnewmsgs = max(area.newmsgs.a + area.newtoyou.a, area.maxnewmsgs)
  541.     area.maxnewtoyou = max(area.newtoyou.a, area.maxnewtoyou)
  542.     area.maxnewfromyou = max(area.newfromyou.a, area.maxnewfromyou)
  543. end
  544.  
  545. area.msgs.0 = area.name.0
  546. return
  547.  
  548.  
  549. PUTDB: procedure expose db. area. total. start. areastamp
  550. say 'Writing '||db.path
  551.  
  552. total.msgs = total.dbmsgs + total.logmsgs
  553. total.toyou = total.dbtoyou + total.logtoyou
  554. total.fromyou = total.dbfromyou + total.logfromyou
  555.  
  556. line.1 = '"'||start.firstdb||'" "'||start.thisdb||'" '||areastamp||' '||total.msgs||' '||total.toyou||' '||total.fromyou
  557. num = 2
  558. do a = 1 to area.name.0
  559.     line.num = area.name.a||' '||area.msgs.a||' '||area.toyou.a||' '||area.fromyou.a
  560.     num = num + 1
  561. end
  562. line.0 = num - 1
  563.  
  564. if ~writefile(db.path, line) then call errorexit('Error writing '||db.path)
  565. return 
  566.  
  567.  
  568. SORTOUTPUT: procedure expose area.
  569. say 'Sorting areas'
  570.  
  571. m = 1                               /* Define m for passes */     
  572. do while (9 * m + 4) < area.msgs.0
  573.     m = m * 3 + 1
  574. end
  575.  
  576. do while m > 0                      /* Sort stem */
  577.     k = area.msgs.0 - m
  578.     do j = 1 to k
  579.         q = j
  580.         do while q > 0
  581.             l = q + m
  582.  
  583.             if area.msgs.q <= area.msgs.l then leave
  584.  
  585.             tmpq = area.name.q||' '||area.msgs.q||' '||area.toyou.q||' '||area.fromyou.q||' '||area.newmsgs.q||' '||area.newtoyou.q||' '||area.newfromyou.q
  586.  
  587.             tmpl = area.name.l||' '||area.msgs.l||' '||area.toyou.l||' '||area.fromyou.l||' '||area.newmsgs.l||' '||area.newtoyou.l||' '||area.newfromyou.l
  588.             parse var tmpl area.name.q area.msgs.q area.toyou.q area.fromyou.q area.newmsgs.q area.newtoyou.q area.newfromyou.q .
  589.  
  590.             parse var tmpq area.name.l area.msgs.l area.toyou.l area.fromyou.l area.newmsgs.l area.newtoyou.l area.newfromyou.l .
  591.  
  592.             q = q - m
  593.         end
  594.     end
  595.     m = m % 3
  596. end
  597. return
  598.  
  599.  
  600. GENOUTPUT: procedure expose start. total. area. out. tosser allareas? toyou?
  601. say 'Writing '||out.path
  602. if total.fromyou > 0 then fromyou? = 1
  603. else fromyou? = 0
  604.  
  605. msg_len = length(area.maxmsgs)       
  606. newmsg_len = length(area.maxnewmsgs)
  607.  
  608. if toyou? then do
  609.     toyou_len = length(area.maxtoyou)
  610.     newtoyou_len = length(area.maxnewtoyou)
  611.     pad_len = msg_len + 1 + 1 + toyou_len + 1 /* A space + '()' */
  612.     if fromyou? then do 
  613.         fromyou_len = length(area.maxfromyou)
  614.         newfromyou_len = length(area.maxnewfromyou)
  615.         pad_len = pad_len + 1 + fromyou_len   /* A space */
  616.     end
  617. end
  618. else pad_len = msg_len
  619.  
  620. select
  621.     when pad_len = 1 then width = 5
  622.     when pad_len = 2 then width = 4
  623.     otherwise width = 3
  624. end
  625. spaces = makespaces(width)
  626. spaces_minus_one = makespaces(width - 1)  /* '100%' kludge */
  627.  
  628. line.1  =  tosser||' mailflow database created by '||subword(sourceline(2), 3, 2)
  629. line.2  =  ''
  630. line.3  =  'Database was started: '||start.firstdb
  631.  
  632. line.4  =  'Messages in database: '||total.msgs
  633. if toyou? then do
  634.     if fromyou? then line.4 = line.4||' ('||total.toyou||' to you, '||total.fromyou||' from you)'
  635.     else line.4 = line.4||' ('||total.toyou||' to you)'
  636. end
  637.  
  638. line.5 = ''
  639.  
  640. line.6  =  'This update: '||start.thisdb
  641. line.7  =  'Last update: '||start.lastdb
  642.  
  643. line.8  =  total.logmsgs||' new messages'
  644. if toyou? then do
  645.     if fromyou? then line.8 = line.8||' ('||total.logtoyou||' to you, '||total.logfromyou||' from you)'
  646.     else line.8 = line.8||' ('||total.logtoyou||' to you)'
  647. end
  648. line.8  =  line.8||' in '||area.name.0||' areas'
  649.  
  650. line.9 = ''
  651.  
  652. line.10 = left('Areaname', area.length)||spaces||left('%', 5)||spaces||,
  653.           left('Total', pad_len + width)||'New'
  654.  
  655. line.11 = ''
  656.  
  657. num = 12                             /* Number of lines in header + 1 */
  658.  
  659. do q = area.msgs.0 to 1 by -1
  660.     if ~allareas? & area.msgs.q = 0 then leave
  661.  
  662.     if toyou? then do
  663.         if fromyou? then do
  664.             youtotal = ' ('||right(area.toyou.q, toyou_len)||' '||right(area.fromyou.q, fromyou_len)||')'
  665.             younew = ' ('||right(area.newtoyou.q, newtoyou_len)||' '||right(area.newfromyou.q, newfromyou_len)||')'
  666.         end
  667.         else do    
  668.             youtotal = ' ('||right(area.toyou.q, toyou_len)||')'
  669.             younew = ' ('||right(area.newtoyou.q, newtoyou_len)||')'
  670.         end
  671.     end
  672.     else do
  673.         youtotal = ''
  674.         younew = ''
  675.     end
  676.     line.num = left(strip(area.name.q), area.length)||spaces_minus_one||,
  677.                format(((area.msgs.q / total.msgs) * 100), 3, 2)||spaces||,
  678.                right(area.msgs.q, msg_len)||youtotal||spaces||,
  679.                right(area.newmsgs.q, newmsg_len)||younew
  680.     num = num + 1
  681. end
  682.  
  683. line.0 = num - 1
  684.  
  685. if ~writefile(out.path, line) then call errorexit('Error writing '||out.path)
  686. return
  687.  
  688.  
  689. /*
  690. ** Generic procedures
  691. */
  692.  
  693. MAKESPACES:
  694. return copies(' ', arg(1))
  695.  
  696. /*
  697. ** format(<number>, [<before>], [<after>])
  698. **
  699. ** If number alone is supplied, the result is the same as that returned by
  700. ** the expression <number> + 0: leading 0's are removed from the number and
  701. ** it is formatted according to the current setting of  NUMERIC DIGITS .
  702. ** 
  703. ** If <before> is supplied, it must be a number equal to or greater than the
  704. ** length in the integer part of <number>. The result will be returned
  705. ** right-justified to <before> spaces.
  706. ** 
  707. ** If <after> is supplied, it must be a number. The fractional part of
  708. ** <number> is rounded (not just truncated) to <after> digits.
  709. */
  710. FORMAT: procedure
  711. arg number, before, after
  712.  
  713. /* Reformats the number to NUMERIC DIGITS setting */
  714. num = number + 0
  715.  
  716. /* Return the reformatted number if other options not specified */
  717. if before = '' & after = '' then return num
  718.  
  719. /* Split the number into fraction and integer */
  720. parse var num integer '.' fraction
  721.  
  722. /* Set defaults for non-spec'd arguments */
  723. if before = '' then before = length(integer)
  724. if after = '' then after = length(fraction)
  725.  
  726. /* [before] argument must be at least as long as integer   */
  727. if before < length(integer) then return '**ERROR**'
  728.  
  729. /* add an appropriate value of .5 to number to round it    */
  730. if after ~= length(fraction) then do
  731.     fraction = trunc(('.'||fraction||'0') + ('.'||copies('0', after)||'5'), after)
  732.     /* Numbers created as text strings are still numbers */
  733.     integer = integer + (fraction % 1)
  734.     fraction = substr(fraction, 3)
  735. end
  736. if fraction >= 0 then return right(integer, before)||'.'||fraction
  737. else return right(integer, before)
  738.  
  739.  
  740. /*  
  741. ** copyfile(sourcefile, destfile) 
  742. */ 
  743. COPYFILE: procedure
  744. parse arg from, to .
  745.  
  746. sz = word(statef(from), 2)
  747.  
  748. call open('s', from, 'r')
  749. call open('d', to, 'w')
  750.  
  751. do (sz % 65535) + 1      
  752.     call writech('d', readch('s', 65535))
  753. end
  754.  
  755. call close('d')
  756. call close('s')
  757. return
  758.  
  759.  
  760. /*  
  761. ** appendfile(sourcefile, destfile) 
  762. */ 
  763. APPENDFILE: procedure
  764. parse arg from, to .
  765.  
  766. sz = word(statef(from), 2)
  767.  
  768. call open('s', from, 'r')
  769. call open('d', to, 'a')
  770.  
  771. do (sz % 65535) + 1      
  772.     call writech('d', readch('s', 65535))
  773. end
  774.  
  775. call close('d')
  776. call close('s')
  777. return
  778.  
  779.  
  780. /*
  781. ** Use while developing...
  782. */
  783. SYNTAX:
  784. ERROR:
  785. trace o
  786. err = rc ; line = sigl
  787. if datatype(err, 'n') then do
  788.     errline = 'Error '||err||': '||errortext(err)||'0a'x||'in line '||line
  789.     sayit? = 1
  790.     if show('p', 'rexx_ced') then do
  791.         parse source . . filename .
  792.         options results
  793.         address 'rexx_ced'
  794.         'cedtofront'
  795.         'ow' filename
  796.         'jump to line' line
  797.         'okay1' errline
  798.         sayit? = 0
  799.     end
  800.     else say errline
  801. end
  802. exit
  803.